package org.enhance.common.util.algorithm;

import org.apache.commons.collections4.CollectionUtils;
import org.enhance.common.model.po.GeoMultiPolygon;
import org.enhance.common.model.po.GeoPoint;
import org.enhance.common.model.po.GeoPolygon;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * @author JiangGengchao
 * @classname GisBaseUtil
 * @description gis基础工具
 * @date 2022-06-29
 **/
public class GisUtil extends GisAlgorithmUtil {
	private GisUtil() {
		super();
		throw new IllegalStateException("Constant class");
	}

	public static GeoPoint getCenterByPolygon(GeoPolygon polygon) {
		return getCenterByPointList(polygon.getGeoPoints());
	}

	public static GeoPoint getCenterByMultiPolygon(GeoMultiPolygon multiPolygon) {
		List<GeoPoint> geoPointList = new ArrayList<>();
		for (GeoPolygon polygon : multiPolygon.getMultiPolygons()) {
			geoPointList.addAll(polygon.getGeoPoints());
		}
		return getCenterByPointList(geoPointList);
	}

	public static GeoPoint getCenterByPointList(List<GeoPoint> geoPointList) {
		if (CollectionUtils.isNotEmpty(geoPointList)) {
			BigDecimal lng = new BigDecimal(0);
			BigDecimal lat = new BigDecimal(0);
			BigDecimal alt = new BigDecimal(0);

			boolean altHasValue = false;
			for (GeoPoint geoPoint : geoPointList) {
				lng = lng.add(geoPoint.getLongitude());
				lat = lat.add(geoPoint.getLatitude());
				if (geoPoint.getAltitude() != null) {
					altHasValue = true;
					alt = alt.add(geoPoint.getAltitude());
				}
			}

			BigDecimal size = BigDecimal.valueOf(geoPointList.size());
			lng = lng.divide(size, 6, BigDecimal.ROUND_HALF_UP);
			lat = lat.divide(size, 6, BigDecimal.ROUND_HALF_UP);
			if (altHasValue) {
				alt = alt.divide(size, 6, BigDecimal.ROUND_HALF_UP);
			} else {
				alt = null;
			}

			return new GeoPoint(lng, lat, alt);
		}
		return null;
	}

	/**
	 * 获取最远点
	 *
	 * @param points
	 * @param target
	 * @return
	 */
	public static GeoPoint getMaximumRangePoint(List<GeoPoint> points, GeoPoint target) {
		GeoPoint maxRangePoint = null;
		if(CollectionUtils.isNotEmpty(points) && target != null) {
			maxRangePoint = new GeoPoint(BigDecimal.ZERO, BigDecimal.ZERO);
			BigDecimal maxLongitudeDistance = BigDecimal.ZERO;
			BigDecimal maxLatitudeDistance = BigDecimal.ZERO;
			for (GeoPoint point : points) {
				BigDecimal longitudeDistance = target.getLongitude().subtract(point.getLongitude()).abs();
				if(longitudeDistance.compareTo(maxLongitudeDistance) == 1) {
					maxLongitudeDistance = longitudeDistance;
					maxRangePoint.setLongitude(point.getLongitude());
				}
				BigDecimal latitudeDistance = target.getLatitude().subtract(point.getLatitude()).abs();
				if(latitudeDistance.compareTo(maxLatitudeDistance) == 1) {
					maxLatitudeDistance = latitudeDistance;
					maxRangePoint.setLatitude(point.getLatitude());
				}
			}
		}
		return maxRangePoint;
	}


	/**
	 * 获取最远点
	 *
	 * @param points
	 * @param target
	 * @return
	 */
	public static GeoPoint getFarthestPoint(List<GeoPoint> points, GeoPoint target) {
		GeoPoint farthestPont = null;
		if(CollectionUtils.isNotEmpty(points) && target != null) {
			double maxDistance = 0;
			for (GeoPoint point : points) {
				double simpleDistance = getSimpleMathDistance(point, target);
				if(simpleDistance > maxDistance) {
					farthestPont = point;
					maxDistance = simpleDistance;
				}
			}
		}
		return farthestPont;
	}
}
